<!-- eslint-disable -->
<template>
  <div class="basic-form">
    <el-form :model="props.model" :inline="inline" :label-width="labelWidth">
      <el-form-item
        v-for="formItem in schemas"
        :key="formItem.field"
        :label="formItem.label"
        :label-width="formItem.labelWidth ?? labelWidth"
      >
        <slot v-if="slots[formItem.field]" :name="formItem.field"></slot>
        <el-input
          v-else-if="
            formItem.type === 'text' || formItem.type === 'password' || formItem.type === 'textarea'
          "
          :style="{ minWidth: inline ? '200px' : 'auto' }"
          v-model.trim="props.model[formItem.field]"
          :type="formItem.type"
          :clearable="formItem.clearable ?? true"
          :class="formItem.className"
          :minlength="formItem.minlength ?? 0"
          :maxlength="formItem.maxlength ?? 142"
          :show-word-limit="formItem.showWordLimit"
          :rows="formItem.rows ?? 2"
          :show-password="(formItem.showPassword ?? true) && formItem.type === 'password'"
          :disabled="formItem.disabled"
          :readonly="formItem.readonly"
          :placeholder="getPlaceholder(formItem.type, formItem.placeholder)"
          @change="handleFormItemChange(formItem)"
          @input="
            ($event:string) => {
              handleValueFormatter($event, formItem)
            }
          "
        />
        <el-input-number
          v-else-if="formItem.type === 'number'"
          v-model.trim="props.model[formItem.field]"
          :clearable="formItem.clearable ?? true"
          :class="formItem.className"
          :min="formItem.min || -Infinity"
          :max="formItem.max || Infinity"
          :step="formItem.step || 1"
          :disabled="formItem.disabled"
          :readonly="formItem.readonly"
          :placeholder="getPlaceholder(formItem.type, formItem.placeholder)"
          @change="handleFormItemChange(formItem)"
        />
        <el-select
          v-else-if="formItem.type === 'select'"
          v-model="props.model[formItem.field]"
          :class="formItem.className"
          :popper-class="formItem.popperClass"
          :clearable="formItem.clearable ?? true"
          filterable
          :teleported="formItem.teleported ?? true"
          :disabled="formItem.disabled"
          :multiple="formItem.multiple"
          :multiple-limit="formItem.multipleLimit ?? 0"
          :collapse-tags="formItem.collapseTags ?? true"
          :collapse-tags-tooltip="formItem.collapseTagsTooltip ?? true"
          :placeholder="getPlaceholder(formItem.type, formItem.placeholder)"
          @focus="handleFormItemFocus(formItem)"
        >
          <el-option
            v-for="selectItem in formItem.options ?? []"
            :key="
              selectItem[
                formItem.optionsFrom === 'dict' ? 'dictValue' : formItem.props?.value || 'value'
              ]
            "
            :label="
              selectItem[
                formItem.optionsFrom === 'dict' ? 'dictLabel' : formItem.props?.label || 'label'
              ]
            "
            :value="
              selectItem[
                formItem.optionsFrom === 'dict' ? 'dictValue' : formItem.props?.value || 'value'
              ]
            "
          />
        </el-select>
        <el-cascader
          v-else-if="formItem.type === 'cascader'"
          v-model="props.model[formItem.field]"
          :class="formItem.className"
          :popper-class="formItem.popperClass"
          :options="formItem.options ?? []"
          :props="formItem.props ?? {}"
          :clearable="formItem.clearable ?? true"
          filterable
          :disabled="formItem.disabled"
          :show-all-levels="formItem.showAllLevels ?? true"
          :teleported="formItem.teleported ?? true"
          :collapse-tags="formItem.collapseTags ?? true"
          :collapse-tags-tooltip="formItem.collapseTagsTooltip ?? true"
          :separator="formItem.separator ?? '/'"
          :placeholder="getPlaceholder(formItem.type, formItem.placeholder)"
          @focus="handleFormItemFocus(formItem)"
        />
        <el-tree-select
          v-else-if="formItem.type === 'treeSelect'"
          v-model="props.model[formItem.field]"
          :class="formItem.className"
          :popper-class="formItem.popperClass"
          :data="formItem.options ?? []"
          :props="formItem.props ?? {}"
          :check-strictly="formItem.props?.checkStrictly ?? false"
          :clearable="formItem.clearable ?? true"
          filterable
          :default-expand-all="formItem.defaultExpandAll ?? false"
          :teleported="formItem.teleported ?? true"
          :disabled="formItem.disabled"
          :multiple="formItem.multiple"
          :multiple-limit="formItem.multipleLimit || 0"
          :collapse-tags="formItem.collapseTags ?? true"
          :collapse-tags-tooltip="formItem.collapseTagsTooltip ?? true"
          :placeholder="getPlaceholder(formItem.type, formItem.placeholder)"
          @focus="handleFormItemFocus(formItem)"
        />
        <el-date-picker
          v-else-if="singleDateTypeList.includes(formItem.type)"
          v-model="props.model[formItem.field]"
          :class="formItem.className"
          :popper-class="formItem.popperClass"
          :type="formItem.type"
          :clearable="formItem.clearable ?? true"
          :format="
            formItem.format ?? 'YYYY-MM-DD' + (formItem.type === 'datetime' ? ' HH:mm:ss' : '')
          "
          :value-format="
            formItem.valueFormat ?? 'YYYY-MM-DD' + (formItem.type === 'datetime' ? ' HH:mm:ss' : '')
          "
          :disabled="formItem.disabled"
          :readonly="formItem.readonly"
          :disabled-date="(time:Date) => getDisabledDate(time, formItem)"
          :teleported="formItem.teleported ?? true"
          :placeholder="getPlaceholder(formItem.type, formItem.placeholder)"
        />
        <el-date-picker
          v-else-if="rangeDateTypeList.includes(formItem.type)"
          v-model="props.model[formItem.field]"
          :class="formItem.className"
          :popper-class="formItem.popperClass"
          :type="formItem.type"
          :clearable="formItem.clearable ?? true"
          :format="
            formItem.format || 'YYYY-MM-DD' + (formItem.type === 'datetimerange' ? ' HH:mm:ss' : '')
          "
          :value-format="
            formItem.valueFormat ||
            'YYYY-MM-DD' + (formItem.type === 'datetimerange' ? ' HH:mm:ss' : '')
          "
          :disabled="formItem.disabled"
          :readonly="formItem.readonly"
          :disabled-date="(time:Date) => getDisabledDate(time, formItem)"
          :teleported="formItem.teleported ?? true"
          :default-time="defaultTime"
          :unlink-panels="formItem.unlinkPanels ?? true"
          :start-placeholder="
            getPlaceholder(formItem.type, formItem.startPlaceholder ?? '开始时间')
          "
          :end-placeholder="getPlaceholder(formItem.type, formItem.endPlaceholder ?? '结束时间')"
        />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" style="margin-left: 10px" @click="handleEmitEvent('search')">
          查询
        </el-button>
        <el-button type="warning" @click="handleEmitEvent('reset')">重置</el-button>
        <!-- <div class="transform-block">
          <SvgIcon name="transform" class-name="t-b-icon" />
        </div> -->
        <slot v-if="slots['btn']" name="btn"></slot>
      </el-form-item>
    </el-form>
  </div>
</template>
<script setup name="BasicForm" lang="ts">
import axios from 'axios'
import { useSlots, computed, watch } from 'vue'

const slots = useSlots()

const emit = defineEmits(['change', 'search', 'reset'])

const props = withDefaults(
  defineProps<{
    model: Recordable
    schemas: FormSchema[]
    inline?: boolean
    labelWidth?: string
  }>(),
  {
    labelWidth: '80px'
  }
)
// 后台请求ip
const requestIp = computed(() => import.meta.env.VITE_BASE_API)

const singleDateTypeList = ['date', 'datetime', 'week', 'month', 'year', 'dates']
const rangeDateTypeList = ['daterange', 'datetimerange', 'monthrange', 'yearrange']

const defaultTime: Date[] = [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]

// 获取"占位符"
const getPlaceholder = (placeholderType: string, placeholderText: string | undefined) => {
  if (['text', 'textarea', 'number', 'password'].includes(placeholderType)) {
    return placeholderText || '请输入'
  }
  return placeholderText || '请选择'
}
// 获取"禁用日期"
const getDisabledDate = (time: Date, formItem: FormSchema): boolean => {
  if (formItem.disabledDateType) {
    const disabledDateTypeMap = {
      before: time.getTime() < Date.now() - 8.64e7,
      after: time.getTime() > Date.now()
    }
    return disabledDateTypeMap[formItem.disabledDateType]
  }
  return false
}

const handleFormItemChange = (formItem: FormSchema): void => {
  emit('change', formItem)
}
const handleFormItemFocus = async (formItem: FormSchema) => {
  // 如果options有值，说明已经获取过了，不需要再次获取
  if (formItem.optionState && formItem.options && formItem.options.length > 0) {
    return false
  }
  switch (formItem.optionsFrom) {
    // 模拟通过字典dict获取
    case 'dict':
      // formItem.options = dictStore.getDictInfo[formItem.dictType ?? 'empty']?.options || []
      formItem.options = []
      break
    // 通过前端提供api方法获取
    case 'frontendApi':
      try {
        if (formItem.optionsApi) {
          const { code, data } = await formItem.optionsApi()
          if (code === 0 || code === 200) {
            formItem.options = data
          }
        }
      } catch (e) {
        console.log(e)
      }
      break
    // 通过后端提供api url与方式 获取
    case 'backendApi':
      axios[formItem.optionsApiType ?? 'get'](requestIp.value + formItem.optionsApi)
        .then(res => {
          const { code, data } = res.data
          if (code === 200 || code === 0) {
            formItem.options = data
          }
        })
        .catch(err => {
          console.log(err)
        })
      break
    default:
      break
  }
  // 已经获取过options
  formItem.optionState = true
  return false
}

const handleValueFormatter = (val: string, formItem: FormSchema): void => {
  if (formItem.formatter && formItem.type !== 'number') {
    // eslint-disable-next-line vue/no-mutating-props
    props.model[formItem.field] = val.replace(formItem.formatter, '')
  }
}
const handleEmitEvent = (type: 'search' | 'reset' | 'change'): void => {
  emit(type)
}
watch(
  () => props.schemas,
  (newVal, oldVal) => {
    // 只有首次加载时，如果设置optionsImmediate,则直接调取接口数据赋值给options
    if (!oldVal) {
      const immediateList = newVal.filter(
        item => item.optionsImmediate && ['select', 'cascader', 'treeSelect'].includes(item.type)
      )
      immediateList.forEach(formItem => {
        handleFormItemFocus(formItem)
      })
    }
  },
  { immediate: true, deep: true }
)
</script>
